- 無關痛癢純發洩的前言
估計 30 天只能寫到第二本 Orz
本來預計 30 天打發時間,整理一下筆記就可以出文章,其他時間研究 React。
結果一直查 spec 查到回過神,
一篇看起來文章沒多長,但資訊密度爆炸多的爛文,我寫得爛 :(
平均每一篇寫 4 小時以上,我的 React 沒什麼時間看 ,也沒什麼時間看太多人的文章 QQ
還在思考繼續提高文章密度讀者會不會直接拉到最下面 skip ...
有些人可能會說,「我寫 JavaScript 不會有 型別轉換(coercion) 問題,型別轉換(coercion) 是 JavaScript 最怪、最多 bug 的地方,我不用就可以了。 」
但是呢,其實不可能避免 型別轉換(coercion)。
以下舉幾個隱性的型別轉換,但幾乎天天用的例子。
這個是大家最熟悉的好朋友,我相信很少人願意自己慢慢用
+
去串接字串。
猜猜看會發生什麼?
哇,你好聰明哦。是 型別轉換(coercion) 呢! (被打
484 開始覺得,其實有 型別轉換(coercion) 自動處理型別問題,真的寫起來潮爽德~
順帶一提,這邊圈起來的地方,前面提過非常多次但都沒有講到的加法 多載
XD
plus operator (+)
偏好 hint string --> ToString() 抽象運算子[day07] YDKJS (Type/Coercion) : Type總結 和 abstract operations (Spec.)
[day08] YDKJS (Coercion:spec) : 回來讀 spec. ToString(), ToNumber() , ToBoolean()
plus operator (+)
兩邊任一邊有 string
, 都會做 ToString()補個舊版中文,一樣是
第 7 點
當然,你可以很固執故意這樣寫,然後說沒有用到 型別轉換(coercion)
array join 的 build-in function, 預設回傳值的型別 是 string.
another :
但上面的例子也觸發 型別轉換(coercion), 因為 Primitive type 沒有 method,
後面會提到,這也是一種隱性的型別轉換(implicit coercion) 。
先大概補個坑(
後面會提到
用太多次了) :
如果你前面文章的 reference 有認真看,應該會知道 toString() 本身會被覆寫,所以要看本身怎麼被觸發的,也就是前面跟的對象是誰。
這邊的 numStudents 其實先 boxing 成 string objects 再取用String.toString()
,boxing 的瞬間就完成 coercion 動作。
boxing 的原因是因為數字是原始型別,沒有方法可以調用,可以調用的原因是背後 Boxing Wrappers 機制。詳細 Boxing Wrappers 後面文章會提到,書裡面也有寫。
如果你不想出現任何 隱性型別轉換(implicit coercion),讓你的 code 看起來很奇怪或是像魔法(magical things),那就用明確型別轉型(explicit coercion) 。
如果使用到大量表單,在做表單處理時,很容易變成字串相加 :
常見會這樣處理:
Unary Operator (+)
一樣給個舊版中文參考
但其實是 Unary Operator (+) , 一元運算子 (+)
觸發 型別轉換(coercion),
實際是 ToPrimitive() hint number => ToNumber()
+inputElement.value
""(空字串)
+ inputElement.valueNumber
+ Number
= Number
註:不要忘記 toNumber("") // 空字串
==> 0
如果你不想出現 magical things,考慮以下用法:
Kyle Simpson 也偏好這樣使用,因為一元運算子很容易和加法運算子混肴。
減法只做 數字運算(numeric) hint toNumber()
如果丟字串就回傳 NaN 。
var numVar = 20 ;
var q_1 = +numVar; // 0 (數字) => 一元運算子 hint number
var q_2 = "" + numVar ; // '0' (字串) => 加法運算子 ,如果有string , hint 就是 string ,做字串相加
書本內的瘋狂例子 :1 + - + + + - + 1; // 2
主要的知識點是 一元運算的正負會抵消,但是連續 + +
(有空格) 和 ++
(遞增運算子)不同
1 + - + + + - (+ 1);
// 一元運算正號 會轉數字1 + - + + + - (1);
// 一元運算負號 也會轉數字,如果可以數字結束後再加上負號1 + - + + + (- 1);
// 遇到連續 一元運算正號,一樣轉數字(連續消除三個 一元運算正號 ),結果還是 -11 + - (- 1);
// 一元運算負號 再加上負號 , -(-1) = 1
1 + 1;
這邊是二元加法符號,兩邊都是數字就純數字相加 = 2 。
如果開頭是字串就變成字串相加 "1" + 1 = "11"
Reference
任何相等
改用條件Boolean(0)
當作 false , 如 if(studentsInputElem.value){...}
dothing.length > 0
,才有意義。假設 studentsInputElem.value = 0
, if(0) === false
語意上來說不合理 。
真實世界的數值 0 其意義不會 falsy ,條件才有可能是 falsy。
註:Boolean 只是純查表,不會做演算法遞迴。
舊版中文
function Account(cash) {
this.cash = cash;
this.isCashHere = !cash;
this.hasMoney = !!cash;
this.useThis = Boolean(cash);
}
var account = new Account(100);
console.log(account.cash); //100
console.log(account.isCashHere); // !(true) === false ?! 小心不要用錯
console.log(account.hasMoney); // !!(true) === !(false) === true
console.log(account.useThis); // true ,純查表
Boolean 真的只是查表
,所以第 8 行
不會變成空字串。
原始型別 Primitive type
怎麼做到 Objects 可以做到的事?
因為 JavaScript 認為自己很聰明,幫你在 JavaScript認為合適的地方
都隱性轉型(implicit coercion)成物件。
如果你寫 Java , 可以這樣理解 new String("abc")
但是你寫的是 JavaScript , 用 new
會產生很多狀況,比如產生物件實體:
var a = new Boolean( false ); // a 這時候是 truthy,因為是物件
if (!a) { // !truthy = false ,永遠不會執行
console.log( "Oops" ); // never runs
}
其實我前面寫過兩次了。
Reference code : MDN
typeof new Boolean(true) === 'object'; // 這樣會令人混淆。不要這樣用!
typeof new Number(1) === 'object'; // 這樣會令人混淆。不要這樣用!
typeof new String("abc") === 'object'; // 這樣會令人混淆。不要這樣用!
順帶一提,其實這個術語沒有出現在 spec.中,
然後書上也沒有寫,本來想追看看 spec. 有沒有規範這個狀態
如何實作,
不過 spec. 只有寫入 [[internalSlots]]
。 也可能是我理解有錯。
abstract operation : ToObject 7.1.13
.
的時候呼叫 abstract operation 的 ToObject
, 並傳入 argument可以解釋 Undefined , Null
Throw a TypeError exception.
[[internalSlots]]
) 寫入 如 [[BooleanData]] 的標記 (tag)舉例 初始化 Constructor
的演算法 來說,OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] )
,
依序傳入三個參數,由此辨認是來自 constructor 還是 Proto,最後才是 ToObject
寫入的 [[internalSlots]] 。
後面就沒追了,因為是 Constructor 的細節。